package archive

import (
	"context"
	"strings"

	"gitlab.com/gitlab-org/gitaly/v14/internal/git/localrepo"
	"gitlab.com/gitlab-org/gitaly/v14/internal/gitaly/archive"
	"gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

// FindArchivedRefs implements the FindArchivedRefs RPC method
func (s *server) FindArchivedRefs(req *gitalypb.FindArchivedRefsRequest, stream gitalypb.ArchiveService_FindArchivedRefsServer) error {
	if req.GetRepository() == nil {
		return status.Error(codes.InvalidArgument, "repository is required")
	}

	ctx := stream.Context()

	// Ensure archive repository exists
	archiveRepo, err := s.storageManager.EnsureArchiveRepo(ctx, req.GetRepository())
	if err != nil {
		return status.Errorf(codes.Internal, "failed to get archive repository: %v", err)
	}

	// Create local repository instance
	localRepo := localrepo.NewTestRepo(s.cfg, archiveRepo)

	// Determine ref prefix to search
	refPrefix := "refs/"
	if req.GetRefType() != "" {
		refPrefix = "refs/" + req.GetRefType() + "/"
	}

	// List all refs in archive repository
	refs, err := s.gitOperations.ListRefs(ctx, archiveRepo, refPrefix)
	if err != nil {
		return status.Errorf(codes.Internal, "failed to list archived refs: %v", err)
	}

	// Apply pagination
	page := req.GetPage()
	if page <= 0 {
		page = 1
	}
	pageSize := req.GetPageSize()
	if pageSize <= 0 {
		pageSize = 10
	}

	start := (page - 1) * pageSize
	end := start + pageSize

	count := 0
	var responseRefs []*gitalypb.FindArchivedRefResponse

	for refName, commitID := range refs {
		// Parse archived ref name to get original ref name
		originalRef, _ := archive.ParseArchivedRefName(refName)

		// Apply filters
		if req.GetRefType() != "" && !strings.HasPrefix(refName, "refs/"+req.GetRefType()+"/") {
			continue
		}

		// Apply refname filter
		if req.GetRefname() != "" && !strings.Contains(originalRef, req.GetRefname()) {
			continue
		}

		// Apply commit_id filter
		if req.GetCommitId() != "" && commitID != req.GetCommitId() {
			continue
		}

		// Apply pagination
		if count < int(start) {
			count++
			continue
		}
		if count >= int(end) {
			break
		}

		// Get commit information
		commit, err := localRepo.ReadCommit(ctx, commitID)
		if err != nil {
			// Skip if commit can't be read, but continue processing other refs
			count++
			continue
		}

		refResponse := &gitalypb.FindArchivedRefResponse{
			Name:     []byte(originalRef),
			CommitId: commitID,
		}

		if commit != nil {
			refResponse.CommitSubject = commit.Subject
			refResponse.Commit = commit
			if commit.Author != nil {
				refResponse.CommitAuthor = &gitalypb.FindArchivedRefCommitAuthor{
					Name:     commit.Author.Name,
					Email:    commit.Author.Email,
					Date:     commit.Author.Date,
					Timezone: commit.Author.Timezone,
				}
			}
			if commit.Committer != nil {
				refResponse.CommitCommitter = &gitalypb.FindArchivedRefCommitAuthor{
					Name:     commit.Committer.Name,
					Email:    commit.Committer.Email,
					Date:     commit.Committer.Date,
					Timezone: commit.Committer.Timezone,
				}
			}
		}

		responseRefs = append(responseRefs, refResponse)
		count++
	}

	// Send response as stream
	if len(responseRefs) > 0 {
		return stream.Send(&gitalypb.FindArchivedRefsResponse{
			Refs: responseRefs,
		})
	}

	return nil
}


